#pragma once

#include <atomic>
#include <thread>
// #include <queue>
#include <vector>
#include <mutex>
#include <functional>
#include <iostream>

#define TRY_TIMES 300
// class spin_mutex;
//任务接口
class task
{
public:
    //接口方法必须在子类实现
    virtual void run() = 0;

public:
    //任务清理接口
    virtual void clean()
    {
    }
    //判断任务是否可执行(返回真时任务才会执行)
    virtual bool runnable()
    {
        return true;
    }
};
typedef std::mutex spin_mutex;
// 自旋锁类
// class spin_mutex
// {
// private:
//     std::atomic_flag flag = ATOMIC_FLAG_INIT;

// public:
//     void lock()
//     {
//         while (flag.test_and_set(std::memory_order_acquire));
//     }
//     void unlock()
//     {
//         flag.clear(std::memory_order_release);
//     }
// };

//任务队列
class async_exec_queue
{
private:
    size_t _queue_size;
    size_t _thread_count;

    bool pop(std::shared_ptr<task>& item)
    {
        std::lock_guard<spin_mutex> lk(mtx);
        if (que.empty()) return false;
        item = que.front(); que.erase(que.begin());
        current_exec_tasks.push_back(item);

        return true;
    }

public:
    async_exec_queue()
    {
        this->_queue_size = 0;
    }
    //实现单例模式
    static async_exec_queue* instance()
    {

        static async_exec_queue obj;
        return &obj;
    }
    spin_mutex mtx;
    std::vector<std::shared_ptr<task>> que;
    std::vector<std::shared_ptr<task>> current_exec_tasks;

    template<class T>
    bool remove_repeat(const std::string& plate, const std::string ip)
    {
        std::lock_guard<spin_mutex> lk(mtx);
        for(auto i = que.begin(); i != que.end(); i++)
        {
            task* tsk = i.base()->get();
            if(((T*)tsk)->_plate == plate &&
            ((T*)tsk)->_ip == ip)
            {
                que.erase(i);
                std::cout << "remove_repeat que:" << plate << ",ip:" << ip << std::endl;
                return true;
            }
        }
        // pro_vector(que, plate, channel_id);
        for(auto i = current_exec_tasks.begin(); i != current_exec_tasks.end(); i++)
        {
            task* tsk = i.base()->get();
            if(((T*)tsk)->_plate == plate &&
            ((T*)tsk)->_ip == ip)
            {
                std::cout << "remove_repeat current_exec_tasks:" << plate << ",ip:" << ip << std::endl;
                return false;
            }
        }

        return true;
        // pro_vector(current_exec_tasks, plate, channel_id);
    }
public:
    //中止任务处理
    void stop()
    {
        _thread_count = 0;
    }
    //清空队列
    void clear()
    {
        std::cout << "queue clear!" << std::endl;
        std::lock_guard<spin_mutex> lk(mtx);
        while (que.size() > 0) que.clear();
        current_exec_tasks.clear();
    }
    //判断队列是否为空
    bool empty()
    {
        std::lock_guard<spin_mutex> lk(mtx);
        return que.empty() && current_exec_tasks.empty();
    }
    //获取队列深度
    size_t size()
    {
        std::lock_guard<spin_mutex> lk(mtx);
        return que.size() + current_exec_tasks.size();
    }
    //获取任务线程线
    size_t get_threads() const
    {
        return _thread_count;
    }
    //任务对象入队
    bool push(std::shared_ptr<task> item)
    {
        std::lock_guard<spin_mutex> lk(mtx);
        if (_queue_size > 0 && que.size() + current_exec_tasks.size() >= _queue_size) return false;

        que.push_back(item);
        // std::cout << "push que addr:"<< item.get() <<",size=" << que.size() << std::endl;
        return true;
    }
    //启动任务队列(启动处理线程)
    void start(size_t threads = 4, size_t maxsz = 10000)
    {
        this->_thread_count = threads;
        this->_queue_size   = maxsz;

        for (size_t i = 0; i < threads; i++)
        {
            std::thread(std::bind(&async_exec_queue::run, this)).detach();
        }
    }
    template<class T>
    void print()
    {
        std::lock_guard<spin_mutex> lk(mtx);
        std::cout << "***************====================" << std::endl;
        for(auto i : current_exec_tasks)
        {
            task* tsk = i.get();
            std::string plate = ((T*)tsk)->_plate;
            std::cout << "curr_task plate:" << plate << std::endl;
        }
        for(auto i : que)
        {
            task* tsk = i.get();
            std::string plate = ((T*)tsk)->_plate;
            std::cout << "wait_task plate:" << plate << std::endl;
        }

        std::cout << "===================================" << std::endl;
    }
public:
    //这个方法里面处理具体任务
    void run()
    {
        std::shared_ptr<task> item;

        while (_thread_count > 0)
        {
            if (pop(item))
            {
                if (item->runnable())
                {
                    item->run();
                    item->clean();
                    std::lock_guard<spin_mutex> lk(mtx);
                    for(auto i = current_exec_tasks.begin(); i != current_exec_tasks.end(); i++)
                    {
                        if(i->get() == item.get())
                        {
                            current_exec_tasks.erase(i);
                            break;
                        }
                    }
                }
                else
                {
                    std::lock_guard<spin_mutex> lk(mtx);
                    que.push_back(item);
                }
            }
            else
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
        }
    }
};